#include "stdafx.h"
#include "ZipParser.h"
//looking at the current configuration node, first 
//load any namespaces into the xml DOM
//then collect the sharepoint column name 
//list from the configuration and evaluate each of them
void CZipParser::ParseXMLIntoPropertyBag(MSXML2::IXMLDOMDocument3Ptr propertyDoc,MSXML2::IXMLDOMNodePtr parserAttempt,IParserPropertyBag * pibag)
{
	//Setup any requested name space abbrebrivations
	MSXML2::IXMLDOMNodePtr nameSpacesNode = parserAttempt->selectSingleNode(L"XPathNameSpaces");
	if(nameSpacesNode)
	{
		try
		{
			propertyDoc->setProperty(L"SelectionNamespaces",nameSpacesNode->text);
		}
		catch(_com_error& err)
		{
			//TODO We need to record the bad SelectionNamespaces text
			ATLTRACE("XML Dom error: %d - %s\n", err.Error(), (const char*)err.Description());
			return;
		}
	}

	MSXML2::IXMLDOMNodeListPtr sharePointColumns = NULL;
	try
	{
		sharePointColumns = parserAttempt->selectNodes(L"SharePointColumn");
	}
	catch(_com_error& err)
	{
		//TODO We need to record the bad XML format
		ATLTRACE("XML Dom error: %d - %s\n", err.Error(), (const char*)err.Description());
		sharePointColumns = NULL;
	}
	if(sharePointColumns)
	{
		//Now loop over the columns and execute each xPath expresssion
		LONG listLength = sharePointColumns->length;
		sharePointColumns->reset();
		for(LONG listIndex = 0; listIndex < listLength; listIndex++)
		{
			MSXML2::IXMLDOMNodePtr sharePointColumn = sharePointColumns->nextNode();
			CStringA multiValueDelimiter( MULTI_VALUE_DELIMITER_A);
			MSXML2::IXMLDOMNodePtr multiValueDelimiterNode =  sharePointColumn->attributes->getNamedItem(L"MultiValueDelimiter");
			if(multiValueDelimiterNode)
			{
				multiValueDelimiter = CStringA((BSTR) multiValueDelimiterNode->text);
			}
			MSXML2::IXMLDOMNodePtr columnNameNode =  sharePointColumn->attributes->getNamedItem(L"Name");
			if(columnNameNode)
			{
				AddPropertyValuesToPropertyBagFromXPath(columnNameNode->text,sharePointColumn->text,multiValueDelimiter,propertyDoc, pibag);
			}
		}
	}
}


//If we get here, we have a valid column name a valid source XML file
//and we think we have a valid XPath query from the configuration file
//for this specific parse, so we will fire the XPath query and
//if it returns any results we will pass them to the property bag
//population routine.
void CZipParser::AddPropertyValuesToPropertyBagFromXPath(_bstr_t columnName,_bstr_t xpathExpression,CStringA multiValueDelimiter, MSXML2::IXMLDOMDocument3Ptr propertyDoc,IParserPropertyBag * pibag)
{
	_bstr_t wildCard(L"*");
	CStringA propertyValue;
	MSXML2::IXMLDOMNodeListPtr propertyValueNodes = NULL;
	try
	{
		propertyValueNodes = propertyDoc->selectNodes(xpathExpression);
	}
	catch(_com_error& err)
	{
		//TODO We need to record the bad xpathExpression
		ATLTRACE("XML Dom error: %d - %s\n", err.Error(), (const char*)err.Description());
		propertyValueNodes = NULL;
	}
	if(propertyValueNodes)
	{
		LONG listLength = propertyValueNodes->length;
		propertyValueNodes->reset();
		for(LONG listIndex = 0; listIndex < listLength; listIndex++)
		{
			MSXML2::IXMLDOMNodePtr valueNode = propertyValueNodes->nextNode();
			CStringA nodeValue((BSTR)valueNode->text);
			nodeValue.TrimRight();
			if(wildCard == columnName)
			{
				//If it is a wild card column, then we will try to get the column name
				//from a few simply name lookups on the node, usually there is a name or id 
				//attribute, but if not we will use the actual node name
				CStringA propertyName((BSTR) valueNode->nodeName);
				MSXML2::IXMLDOMNodePtr columnNameHintNode =  valueNode->attributes->getNamedItem(L"name");
				if(NULL == columnNameHintNode) columnNameHintNode =  valueNode->attributes->getNamedItem(L"Name");
				if(NULL == columnNameHintNode) columnNameHintNode =  valueNode->attributes->getNamedItem(L"id");
				if(NULL == columnNameHintNode) columnNameHintNode =  valueNode->attributes->getNamedItem(L"ID");
				if(columnNameHintNode)
				{
					propertyName = CStringA((BSTR) columnNameHintNode->text);
				}
				AddPropertyValuesToPropertyBag(propertyName,nodeValue,pibag);
			}
			else
			{
				//If we are multivalue then build a multivalue string
				propertyValue += CStringA((BSTR)valueNode->text);
				if(listIndex < (listLength -1))
				{
					propertyValue += multiValueDelimiter;
				}
			}
		}
	}
	if(!propertyValue.IsEmpty())
	{
		CStringA propertyName((BSTR)columnName);
		AddPropertyValuesToPropertyBag(propertyName,propertyValue,pibag);
	}
}

 
//Ok we have a property name and a value, so load them into the property bag
//currently we only set text but we could query the type , convert it and
//set it as a typed value, nice for somone to add 
 void CZipParser::AddPropertyValuesToPropertyBag(CStringA propertyName,CStringA propertyValue,IParserPropertyBag * pibag)
 {

	if(NULL != pibag && !propertyName.IsEmpty())
	{
		//if the property exists we are going to update it
		//otherwise we eill add it as a new property
		IParserProperty* lpNewProp = NULL;
		HRESULT hRes = pibag->FindProp(propertyName.GetBuffer(),&lpNewProp);
		if(FAILED(hRes) || NULL == lpNewProp)
		{
			hRes = pibag->NewProp(propertyName.GetBuffer(),&lpNewProp);
		}
		else
		{
			lpNewProp->AddRef();
		}
		if(SUCCEEDED(hRes))
		{
			//only text values in this version
			if(propertyValue.GetLength() > 255)
			{
				hRes = lpNewProp->SetLongText(propertyValue.GetBuffer());
			}
			else
			{
				hRes = lpNewProp->SetShortText(propertyValue.GetBuffer());
			}

			lpNewProp->Release();
		}
	}
 }
